﻿using System.Diagnostics;
using System.Drawing;
using RaytracerLib.MathLib;
using RaytracerLib.Layers.Interpolators;
using RaytracerLib.Layers.OverlayCorrectors;
using TomanuExtensions;
using System.Collections.Generic;

namespace RaytracerLib.Layers
{
    public abstract class ColorArrayBase : ArrayBase
    {
        protected ColorArrayBase(OverlayMethod a_overlayMethod,
            InterpolationMethod a_interpolationMethod)
            : base(a_overlayMethod, a_interpolationMethod)
        {
        }

        public ColorFloat this[int a_x, int a_y]
        {
            get
            {
                return GetColor(a_x, a_y);
            }
            set
            {
                SetColor(a_x, a_y, value);
            }
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public bool IsAlmostRelativeEquals(ColorArrayBase a_ar, float a_precision = Constants.COLOR_PRECISION)
        {
            if (Height != a_ar.Height)
                return false;
            if (Width != a_ar.Width)
                return false;

            for (int y = 0; y < Height; y++)
            {
                for (int x = 0; x < Width; x++)
                {
                    if (!GetColor(x, y).IsAlmostRelativeEquals(a_ar.GetColor(x, y), a_precision))
                        return false;
                }
            }

            return true;
        }

        public void Draw(ColorArrayBase a_src, Rectangle a_src_rect, Rectangle a_dest_rect)
        {
            var desty = a_dest_rect.Top;

            Debug.Assert(a_src_rect.Width == a_dest_rect.Width);
            Debug.Assert(a_src_rect.Height == a_dest_rect.Height);

            for (int srcy = a_src_rect.Top; srcy < a_src_rect.Bottom; srcy++)
            {
                var destx = a_dest_rect.Left;

                for (int srcx = a_src_rect.Left; srcx < a_src_rect.Right; srcx++)
                {
                    SetColor(destx, desty, a_src.GetColor(srcx, srcy));
                    destx++;
                }

                desty++;
            }
        }

        public override void Fill(double a_value)
        {
            Fill(new ColorFloat(a_value));
        }

        public override void Fill(ColorFloat a_color)
        {
            foreach (Point p in Pixels())
                SetColor(p.X, p.Y, a_color);
        }


        /// <summary>
        /// By default we store colors in linear space. Use with caution. Always remember to use SRGBToLinear.
        /// </summary>
        public void LinearToSRGB()
        {
            foreach (Point p in Pixels())
                SetColor(p.X, p.Y, Gamma.LinearToSRGB(GetColor(p.X, p.Y)));
        }

        /// <summary>
        /// By default we store colors in linear space. Use with caution.
        /// </summary>
        public void SRGBToLinear()
        {
            foreach (Point p in Pixels())
                SetColor(p.X, p.Y, Gamma.SRGBToLinear(GetColor(p.X, p.Y)));
        }

        public abstract Bitmap GetBitmap();
        public abstract Bitmap GetBitmap(Rectangle a_rect);
    }
}